package com.ccb.sc.groupon.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ccb.sc.groupon.convert.AppGrouponConvert;
import com.ccb.sc.groupon.mapper.AppGrouponMapper;
import com.ccb.sc.groupon.query.AppGrouponSearchParam;
import com.ccb.sc.groupon.vo.*;
import com.ccb.sc.order.service.IAppOrderService;
//psl import com.ccb.sc.common.bind.exception.BizException;
import com.ccb.sc.common.bind.page.PageParams;
import com.ccb.sc.common.bind.page.PageVo;
import com.ccb.sc.common.bind.query.Filter;
import com.ccb.sc.common.code.BizCodeFace;
import com.ccb.sc.common.code.ErrorCode;
import com.ccb.sc.common.constant.CommonConstant;
import com.ccb.sc.common.modules.groupon.entity.Groupon;
import com.ccb.sc.common.modules.groupon.entity.GrouponLog;
import com.ccb.sc.common.modules.groupon.enums.GrouponStatus;
import com.ccb.sc.common.modules.order.entity.Order;
import com.ccb.sc.common.modules.order.enums.OrderStatus;
import com.ccb.sc.common.modules.setting.service.ISettingsService;
import com.ccb.sc.common.modules.setting.vo.OrderSettingsVo;
import com.ccb.sc.common.util.IdUtil;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author ken
 * @version 1.0
 * @date 2020-09-21
 */
@Service
public class AppGrouponService extends ServiceImpl<AppGrouponMapper, Groupon> {

    @Autowired
    private AppGrouponLogService grouponLogService;

    @Autowired
    @Lazy
    private IAppOrderService orderService;

    @Autowired
    private ISettingsService settingsService;

    public PageVo<AppGrouponListVo> list(AppGrouponSearchParam queryParam) {
        Page<Groupon> page = new Page<>(queryParam.getCurrent(), queryParam.getPageSize());
        AppGrouponMapper.QueryParam params = new AppGrouponMapper.QueryParam();
        if (StringUtils.hasText(queryParam.getKey())) {
            params.setKey(Filter.LikeValue.both(queryParam.getKey()));
        }
        if (queryParam.getCategoryId() != null) {
            params.setCategoryId(queryParam.getCategoryId());
        }
        Page<AppGrouponListVo> records = this.getBaseMapper().selectByQueryParam(page, params);
        return PageVo.create(queryParam.getCurrent(), queryParam.getPageSize(), records.getTotal(), records.getRecords());
    }

    public GrouponStatVo stat(Long memberId) {
        GrouponStatVo statVo = new GrouponStatVo();
        long groupons = this.grouponLogService.count(Wrappers.<GrouponLog>lambdaQuery().eq(GrouponLog::getMemberId, memberId));
        long inviteGroupons = this.grouponLogService.count(Wrappers.<GrouponLog>lambdaQuery().eq(GrouponLog::getInviteId, memberId));
        statVo.setGroupons((int) groupons);
        statVo.setInviteGroupons((int) inviteGroupons);
        return statVo;
    }

    public PageVo<GrouponLogListVo> getRecords(Long memberId, PageParams params) {
        Page<GrouponLog> page = new Page<>(params.getCurrent(), params.getPageSize());
        Page<GrouponLogListVo> records = this.getBaseMapper().selectRecords(page, memberId);
        return PageVo.create(params.getCurrent(), params.getPageSize(), records.getTotal(), records.getRecords());
    }

    public PageVo<GrouponLogListVo> getInviteRecords(Long memberId, PageParams params) {
        Page<GrouponLog> page = new Page<>(params.getCurrent(), params.getPageSize());
        Page<GrouponLogListVo> records = this.getBaseMapper().selectInviteRecords(page, memberId);
        List<GrouponLogListVo> list = records.getRecords();
        if (CollectionUtils.isEmpty(list)) {
            return PageVo.create(params.getCurrent(), params.getPageSize(), 0, list);
        }
        OrderSettingsVo settings = this.settingsService.getSettings(OrderSettingsVo.class);
        BigDecimal headsRatio = Optional.ofNullable(settings.getHeadsRatio()).orElse(new BigDecimal("5"));
        for (GrouponLogListVo vo : list) {
            BigDecimal headsAward = vo.getGrouponPrice().multiply(headsRatio).divide(CommonConstant.HUNDRED, 2, RoundingMode.HALF_UP);
            vo.setCommission(headsAward);
        }
        return PageVo.create(params.getCurrent(), params.getPageSize(), records.getTotal(), list);
    }

    /**
     * 根据商品id查找团购信息
     * @param goodsId 商品id
     * @return Groupon
     */
    public GrouponVo findByGoodsId(Long memberId, Long goodsId) {
        Groupon groupon = this.getOne(Wrappers.<Groupon>lambdaQuery().eq(Groupon::getGoodsId, goodsId).orderByDesc(Groupon::getModifyTime).last("limit 1"));
        if (groupon == null) {
            return null;
        }
        GrouponVo vo = AppGrouponConvert.INSTANCE.entity2Vo(groupon);
        if (memberId != null) {
            long count = this.grouponLogService.count(Wrappers.<GrouponLog>lambdaQuery().eq(GrouponLog::getGrouponId, groupon.getId()).eq(GrouponLog::getMemberId, memberId));
            vo.setHasBuy(count > 0);
        }
        groupon.setViews(groupon.getViews() + 1);
        groupon.setVersion(groupon.getVersion());
        this.updateById(groupon);

        return vo;
    }

    public List<GrouponLog> findByOrderId(Long memberId, List<String> orderIds) {
        return this.grouponLogService.list(Wrappers.<GrouponLog>lambdaQuery().eq(GrouponLog::getMemberId, memberId).in(GrouponLog::getOrderId, orderIds));
    }

    /**
     * 薪资团购记录
     * @param createVo 创建信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void createLog(GrouponCreateVo createVo) {
        // 查找团购信息
        Groupon groupon = this.getOne(Wrappers.<Groupon>lambdaQuery().eq(Groupon::getGoodsId, createVo.getGoodsId()).orderByDesc(Groupon::getModifyTime).last("limit 1"));
        Assert.notNull(groupon, "团购信息不存在！");
        // 如果当前成团人数差1人
        if (groupon.getGroupCurrentSize() == groupon.getGroupTotalSize() - 1) {

            GrouponLog grouponLog = new GrouponLog();
            grouponLog.setMemberId(createVo.getMemberId());
            grouponLog.setInviteId(createVo.getInviteId());
            grouponLog.setOrderId(createVo.getOrderId());
            grouponLog.setGrouponId(groupon.getId());
            grouponLog.setGrouponUuid(groupon.getGrouponUuid());
            grouponLog.setGoodsId(createVo.getGoodsId());
            grouponLog.setGoodsSpecId(createVo.getGoodsSpecId());
            grouponLog.setGrouponPrice(groupon.getGrouponPrice());
            grouponLog.setStartTime(LocalDateTime.now());
            grouponLog.setStatus(GrouponStatus.GROUPING);
            this.grouponLogService.save(grouponLog);

            // 更新当前团成功、
            List<GrouponLog> grouponLogs = this.grouponLogService.list(Wrappers.<GrouponLog>lambdaQuery().eq(GrouponLog::getGrouponId, groupon.getId()).eq(GrouponLog::getGrouponUuid,
                    groupon.getGrouponUuid()));
            List<String> orderIds = new ArrayList<>();
            for (GrouponLog log : grouponLogs) {
                log.setStatus(GrouponStatus.FINISHED);
                log.setEndTime(LocalDateTime.now());
            }
            this.grouponLogService.updateBatchById(grouponLogs);

            // 更新团购信息
            // 开团，生成团购id
            String grouponUuid = IdUtil.getTimeUUID();
            groupon.setGrouponUuid(grouponUuid);
            groupon.setGroupNum(groupon.getGroupNum() + 1);
            groupon.setGroupCurrentSize(0);
            groupon.setVersion(groupon.getVersion());
            boolean updateStatus = this.updateById(groupon);
            if (!updateStatus) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
            }
        }else if(groupon.getGroupCurrentSize() >= groupon.getGroupTotalSize()){
            // 如果当前成团人数=总成团人数，需新开团
            // 生成团购id
            String grouponUuid = IdUtil.getTimeUUID();
            GrouponLog grouponLog = new GrouponLog();
            grouponLog.setMemberId(createVo.getMemberId());
            grouponLog.setInviteId(createVo.getInviteId());
            grouponLog.setOrderId(createVo.getOrderId());
            grouponLog.setGrouponId(groupon.getId());
            grouponLog.setGrouponUuid(grouponUuid);
            grouponLog.setGoodsId(createVo.getGoodsId());
            grouponLog.setGoodsSpecId(createVo.getGoodsSpecId());
            grouponLog.setGrouponPrice(groupon.getGrouponPrice());
            grouponLog.setStartTime(LocalDateTime.now());
            grouponLog.setStatus(GrouponStatus.GROUPING);
            this.grouponLogService.save(grouponLog);

            // 更新上一个团成功、
            List<GrouponLog> grouponLogs = this.grouponLogService.list(Wrappers.<GrouponLog>lambdaQuery().eq(GrouponLog::getGrouponId, groupon.getId()).eq(GrouponLog::getGrouponUuid,
                    groupon.getGrouponUuid()));
            List<String> orderIds = new ArrayList<>();
            for (GrouponLog log : grouponLogs) {
                log.setStatus(GrouponStatus.FINISHED);
                log.setEndTime(LocalDateTime.now());
            }
            this.grouponLogService.updateBatchById(grouponLogs);
            // 更新订单状态信息
            this.orderService.update(Wrappers.<Order>lambdaUpdate().in(Order::getId, orderIds).set(Order::getStatus, OrderStatus.WAIT_DELIVER));

            // 更新团购信息
            groupon.setGrouponUuid(grouponUuid);
            groupon.setGroupNum(groupon.getGroupNum() + 1);
            groupon.setGroupCurrentSize(1);
            groupon.setVersion(groupon.getVersion());
            boolean updateStatus = this.updateById(groupon);
            if (!updateStatus) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
            }
        }else if (groupon.getGroupCurrentSize() == 0){
            // 生成团购id
            String grouponUuid = IdUtil.getTimeUUID();
            
            GrouponLog grouponLog = new GrouponLog();
            grouponLog.setMemberId(createVo.getMemberId());
            grouponLog.setInviteId(createVo.getInviteId());
            grouponLog.setOrderId(createVo.getOrderId());
            grouponLog.setGrouponId(groupon.getId());
            grouponLog.setGrouponUuid(grouponUuid);
            grouponLog.setGoodsId(createVo.getGoodsId());
            grouponLog.setGoodsSpecId(createVo.getGoodsSpecId());
            grouponLog.setGrouponPrice(groupon.getGrouponPrice());
            grouponLog.setStartTime(LocalDateTime.now());
            grouponLog.setStatus(GrouponStatus.GROUPING);
            this.grouponLogService.save(grouponLog);

            groupon.setGrouponUuid(grouponUuid);
            groupon.setGroupCurrentSize(1);
            groupon.setVersion(groupon.getVersion());
            boolean updateStatus = this.updateById(groupon);
            if (!updateStatus) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
            }
        }else {
            GrouponLog grouponLog = new GrouponLog();
            grouponLog.setMemberId(createVo.getMemberId());
            grouponLog.setInviteId(createVo.getInviteId());
            grouponLog.setOrderId(createVo.getOrderId());
            grouponLog.setGrouponId(groupon.getId());
            grouponLog.setGrouponUuid(groupon.getGrouponUuid());
            grouponLog.setGoodsId(createVo.getGoodsId());
            grouponLog.setGoodsSpecId(createVo.getGoodsSpecId());
            grouponLog.setGrouponPrice(groupon.getGrouponPrice());
            grouponLog.setStartTime(LocalDateTime.now());
            grouponLog.setStatus(GrouponStatus.GROUPING);
            this.grouponLogService.save(grouponLog);

            groupon.setGroupCurrentSize(groupon.getGroupCurrentSize() + 1);
            groupon.setVersion(groupon.getVersion());
            boolean updateStatus = this.updateById(groupon);
            if (!updateStatus) {
                //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.FAIL));
            }
        }


    }
}
